背景
项目用到的数据集来自kaggle,共包含1989条记录,每条记录包含每天的Top25条新闻,目标是通过对新闻的词频分析判断股市涨跌。
技术与方法
项目分为四部分:
第一部分是解读数据,主要用到Python文本分析工具NLTK中的分词tokenize,需要说明的是,本项目是对英文做分词处理,单词间以空格作为自然分界符,而中文是根据语义做分词,常用工具是结巴分词,得到分词结果后,中英文后续的处理是一样的。
第二部分是特征工程,包括特征提取、特征选择、特征降维。特征提取使用TF-IDF和Word2Vec结合的方式。TF-IDF是词频-逆文档频率,TF表示某个词在该文件中出现的次数,IDF衡量某个词普遍的重要性。Word2Vec是将语言中字词转为向量形式表达。特征选择使用sklearn中的VarianceThreshold方法,去除方差小的特征。特征降维使用主成分分析PCA方法。
第三部分是模型调参及训练,模型调参使用sklearn的网格搜索GridSearchCV方法,模型训练部分选择朴素贝叶斯、逻辑回归、支持向量机SVC和随机森林四种模型。
第四部分是模型预测与评价,使用accuracy_score指标和混淆矩阵评价分类准确度。
解读数据
处理原始数据集
读取原始数据集:
raw_text_df = pd.read_csv(constant.raw_text_csv_file)

第1列是日期,label为0是跌,label为1是涨,后面25列是新闻内容。接下来对原始数据集进行分词处理,这里用到NLTK的分词工具tokenize,和NLTK语料库中的停用词库stopwords,针对原始数据集的每一条新闻做分词处理,去除停用词,得到分词结果后,将分词后的25列新闻合并为1列,存在cln_text_df[‘text’]中,保存处理后的文件cln_text.csv。
处理后的数据:
分割训练集和测试集
读取cln_text.csv,查看总样本数量:
各类样本数量:
label
0 924
1 1065
正负类别样本量均衡,接下来按时间段分割训练集和测试集,训练集时间范围 2008-08-08 ~ 2014-12-31,测试集时间范围 2015-01-02 ~
2016-07-01。

得到
训练集中各类的数据个数:
label
0 738
1 873
测试集中各类的数据个数:
label
0 186
1 192
特征工程
提取文本特征
这里选择TF-IDF及word2vec特征,对于word2vec简单使用max pooling方法处理。
训练word2vec模型
word2vec可以把字词转为向量形式,参数size是转换后的特征维度(取值100),sg为0时是CBOW模式,为1时是Skip-Gram模式,windows是滑窗尺寸,即寻找相邻词的个数,得到w2v_model.wv即是单词对应的向量。
在训练集上统计词频
将训练集中的单词拿出来放到word_list中,利用NLTK中的词频统计工具FreqDist,统计每个单词出现的次数,这里要注意去除空字符串,否则后续在提取Word2Vec特征时会报错,然后取出现最多的200个词及出现的频率存放在common_words_freqs中:(n_common_words取值200)
得到结果:出现最多的200个词是:
us: 2499次
israel: 1948次
new: 1872次
says: 1841次
world: 1829次
china: 1729次
government: 1724次
police: 1666次
……
在训练集和测试集上提取特征
定义提取特征的函数extract_feat_from_data,遍历输入的数据集的每一行单词和高频词数组common_words,如果高频词有出现在输入的文本,则计算该词在这一行文本的TF-IDF值,同时将训练word2vec生成的wv相应词的向量赋值给w2v_val,最终得到存放了TF-IDF值的tf_idf_feat_val_list和存放了word2vec特征的w2v_feat_val_list。
对w2v_feat_val_list做max
pooling处理,即每列取最大值作为代表特征,再将得到的结果和TF-IDF合并,得到特征矩阵X,每个样本特征维度是300。
1 |
text_collection = TextCollection(train_text_df['text'].values.tolist()) |
特征处理
特征范围归一化
使用sklearn.preprocessing中的StandardScaler工具将特征范围归一化到(-1,1)
1 |
scaler = StandardScaler() |
特征选择
使用sklearn中的特征选择方法VarianceThreshold,去除方差小的特征,这里根据方差保留80%的向量
1 |
sel = VarianceThreshold(threshold=(.8 * (1 - .8))) |
特征选择后每个样本特征维度: 294
特征降维
使用sklearn中的PCA实现特征降维,和特征选择不同,PCA通过线型变换将原数据映射到新的坐标系统中,使映射后的第一个坐标上的方差最大(即第一个主成分),依次递减。这里保留95%贡献率的特征向量。
1 |
pca = PCA(n_components=0.95) # 保留95%贡献率的特征向量 |
处理后每个样本特征维度: 192
模型调参及训练
项目要解决的是分类问题,股市涨跌属于二分类问题,这里选择4种机器学习模型进行预测:朴素贝叶斯,逻辑回归,支持向量机,随机森林。其中朴素贝叶斯不需要调参,其他三个模型都需要参数调优。
训练朴素贝叶斯模型
1 |
models = [] |
训练逻辑回归模型
逻辑回归为了平衡损失函数和正则项的关系,引入了损失函数的系数C作为模型超参数,C越大,损失函数的调节越重要,C越小,正则项的调节越重要。这里对C选取5个值,使用sklearn的网格搜索GridSearchCV进行交叉验证获取最优参数。
1 |
print('2. 逻辑回归:') |
逻辑回归最佳参数: C=10
训练SVC模型
这里对SVC的3个参数进行调优,惩罚因子C:C依然是为了平衡损失函数和正则项的关系,与逻辑回归的C不同的是,SVC的C是正则项的系数,C越大,模型的容错空间越小,越容易过拟合,C越小,模型的容错空间越大,越容易欠拟合;kernel选择高斯核函数,gamma是高斯核函数的系数,gamma越大,高斯分布越窄,越容易过拟合,gamma越小,高斯分布越宽,越容易欠拟合,这里gamma分别取0.001和0.0001。
1 |
print('3. 支持向量机:') |
SVC的最佳参数是:C=0.01,gamma=0.001,kernel=’rbf’
训练随机森林模型
这里选择n_estimators作为调参对象,n_estimators是子模型数量,在临界值内,数量越大,效果越好,但是计算时间也会随之增加。
1 |
print('4. 随机森林:') |
随机森林最佳参数: n_estimators=50
模型预测与评价
使用sklearn的accuracy_score评价分类准确度,得分越高,说明预测准确度越高;
最后输出每个模型的混淆矩阵。
1 |
for i, model in enumerate(models): |
1-朴素贝叶斯
准确率: 0.510582010582
混淆矩阵
[[ 64 122]
[ 63 129]]
2-逻辑回归
准确率: 0.502645502646
混淆矩阵
[[ 71 115]
[ 73 119]]
3-支持向量机
准确率: 0.507936507937
混淆矩阵
[[ 0 186]
[ 0 192]]
4-随机森林
准确率: 0.502645502646
混淆矩阵
[[ 40 146]
[ 42 150]]
可以看出,朴素贝叶斯准确率最高,SVC在预测跌势的能力最差,朴素贝叶斯、逻辑回归和随机森林在预测涨势时比跌势更准确。